home *** CD-ROM | disk | FTP | other *** search
/ Programming a Multiplayer FPS in DirectX / Programming a Multiplayer FPS in DirectX (Companion CD).iso / DirectX / dxsdk_oct2004.exe / dxsdk.exe / Samples / C++ / Direct3D / Instancing / Instancing.cpp next >
Encoding:
C/C++ Source or Header  |  2004-09-27  |  55.6 KB  |  1,239 lines

  1. //--------------------------------------------------------------------------------------
  2. // File: Instancing.cpp
  3. //
  4. // Demonstrates the geometry instancing capability of VS3.0-capable hardware by replicating
  5. // a single box model into a pile of boxes all in one DrawIndexedPrimitive call.
  6. // Also shows alternate ways of doing instancing on non-vs_3_0 HW
  7. //
  8. // Copyright (c) Microsoft Corporation. All rights reserved.
  9. //--------------------------------------------------------------------------------------
  10. #include "dxstdafx.h"
  11. #include "resource.h"
  12.  
  13. //#define DEBUG_VS   // Uncomment this line to debug vertex shaders 
  14. //#define DEBUG_PS   // Uncomment this line to debug pixel shaders 
  15.  
  16.  
  17. //--------------------------------------------------------------------------------------
  18. // Global variables
  19. //--------------------------------------------------------------------------------------
  20. ID3DXFont*              g_pFont = NULL;         // Font for drawing text
  21. ID3DXSprite*            g_pTextSprite = NULL;   // Sprite for batching draw text calls
  22. ID3DXEffect*            g_pEffect = NULL;       // D3DX effect interface
  23. CModelViewerCamera      g_Camera;               // A model viewing camera
  24. bool                    g_bShowHelp = true;     // If true, it renders the UI control text
  25. CDXUTDialog             g_HUD;                  // dialog for standard controls
  26. CDXUTDialog             g_SampleUI;             // dialog for sample specific controls
  27. CDXUTDialog             g_SampleUI2;             // dialog for sample specific controls
  28. bool                    g_bAppIsDebug = false;  // The application build is debug
  29. bool                    g_bRuntimeDebug = false;    // The D3D Debug Runtime was detected
  30. const int               g_nMaxBoxes = 1000;     // max number of boxes to render
  31. int                     g_NumBoxes = 500;       // current number of boxes
  32. const int               g_nNumBatchInstance = 120;  // number of batched instances; must be the same size as g_nNumBatchInstance from .fx file
  33. int                     g_nBurnCPU = 0;         // %CPU binded to other task
  34. int                     g_iUpdateCPUUsageMessage = 0;   // controls when to update the CPU usage static control
  35. const double            g_fBurnInterval = 0.01;  // period between burns
  36. double                  g_fBurnAmount = 0.0;    // time in seconds to burn for during each burn period
  37. D3DXHANDLE              g_HandleTechnique;      // handle to the rendering technique
  38. D3DXHANDLE              g_HandleWorld, g_HandleView, g_HandleProjection;    // handle to the world/view/projection matrixes
  39. D3DXHANDLE              g_HandleTexture;        // handle to the box texture
  40. D3DXHANDLE              g_HandleBoxInstance_Position;   // handle to the box instance position (array or the value itself)
  41. D3DXHANDLE              g_HandleBoxInstance_Color;      // handle to the box instance color (array or the value itself)
  42. IDirect3DTexture9*      g_pBoxTexture;          // Texture covering the box
  43. WORD                    g_iRenderTechnique = 1; // the currently selected rendering technique
  44. D3DXVECTOR4             g_vBoxInstance_Position[ g_nMaxBoxes ]; // instance data used in shader instancing (position)
  45. D3DXCOLOR               g_vBoxInstance_Color[ g_nMaxBoxes ];    // instance data used in shader instancing (color)
  46.  
  47. //--------------------------------------------------------------------------------------
  48. //This VB holds float-valued normal, position and texture coordinates for the model (in this case, a box)
  49. //This will be stream 0
  50. IDirect3DVertexBuffer9 * g_pVBBox=0;
  51. IDirect3DIndexBuffer9 *  g_pIBBox=0;
  52.  
  53. // Format of the box vertices for HW instancing
  54. struct BOX_VERTEX
  55. {
  56.     D3DXVECTOR3 pos;    // Position of the vertex
  57.     D3DXVECTOR3 norm;   // Normal at this vertex
  58.     float u, v;         // Texture coordinates u,v
  59. };
  60.  
  61. // Format of the box vertices for shader instancing
  62. struct BOX_VERTEX_INSTANCE
  63. {
  64.     D3DXVECTOR3 pos;    // Position of the vertex
  65.     D3DXVECTOR3 norm;   // Normal at this vertex
  66.     float u, v;         // Texture coordinates u,v
  67.     float boxInstance;  // Box instance index
  68. };
  69.  
  70.  
  71. //--------------------------------------------------------------------------------------
  72. //This VB holds the positions for copies of the basic box within the pile of boxes.
  73. //The positions are expressed as bytes in a DWORD:
  74. //  byte 0: x position
  75. //  byte 1: y position
  76. //  byte 3: height of box
  77. //  byte 4: azimuthal rotation of box
  78. //This will be stream 1
  79. IDirect3DVertexBuffer9 * g_pVBInstanceData=0;
  80.  
  81. //Here is the format of the box positions within the pile:
  82. struct BOX_INSTANCEDATA_POS
  83. {
  84.     D3DCOLOR color;
  85.     BYTE    x;
  86.     BYTE    y;
  87.     BYTE    z;
  88.     BYTE    rotation;
  89. };
  90.  
  91.  
  92. //--------------------------------------------------------------------------------------
  93. // Vertex Declaration for Hardware Instancing
  94. IDirect3DVertexDeclaration9 *g_pVertexDeclHardware = NULL;
  95. D3DVERTEXELEMENT9 g_VertexElemHardware[] = 
  96. {
  97.     { 0, 0,     D3DDECLTYPE_FLOAT3,     D3DDECLMETHOD_DEFAULT,  D3DDECLUSAGE_POSITION,  0 },
  98.     { 0, 3 * 4, D3DDECLTYPE_FLOAT3,     D3DDECLMETHOD_DEFAULT,  D3DDECLUSAGE_NORMAL,    0 },
  99.     { 0, 6 * 4, D3DDECLTYPE_FLOAT2,     D3DDECLMETHOD_DEFAULT,  D3DDECLUSAGE_TEXCOORD,  0 },
  100.     { 1, 0,     D3DDECLTYPE_D3DCOLOR,   D3DDECLMETHOD_DEFAULT,  D3DDECLUSAGE_COLOR,     0 },
  101.     { 1, 4,     D3DDECLTYPE_D3DCOLOR,   D3DDECLMETHOD_DEFAULT,  D3DDECLUSAGE_COLOR,     1 },
  102.     D3DDECL_END()
  103. };
  104.  
  105. // Vertex Declaration for Shader Instancing
  106. IDirect3DVertexDeclaration9 *g_pVertexDeclShader = NULL;
  107. D3DVERTEXELEMENT9 g_VertexElemShader[] = 
  108. {
  109.     { 0, 0,     D3DDECLTYPE_FLOAT3,     D3DDECLMETHOD_DEFAULT,  D3DDECLUSAGE_POSITION,  0 },
  110.     { 0, 3 * 4, D3DDECLTYPE_FLOAT3,     D3DDECLMETHOD_DEFAULT,  D3DDECLUSAGE_NORMAL,    0 },
  111.     { 0, 6 * 4, D3DDECLTYPE_FLOAT2,     D3DDECLMETHOD_DEFAULT,  D3DDECLUSAGE_TEXCOORD,  0 },
  112.     { 0, 8 * 4, D3DDECLTYPE_FLOAT1,     D3DDECLMETHOD_DEFAULT,  D3DDECLUSAGE_TEXCOORD,  1 },
  113.     D3DDECL_END()
  114. };
  115.  
  116. // Vertex Declaration for Constants Instancing
  117. IDirect3DVertexDeclaration9 *g_pVertexDeclConstants = NULL;
  118. D3DVERTEXELEMENT9 g_VertexElemConstants[] = 
  119. {
  120.     { 0, 0,     D3DDECLTYPE_FLOAT3,     D3DDECLMETHOD_DEFAULT,  D3DDECLUSAGE_POSITION,  0 },
  121.     { 0, 3 * 4, D3DDECLTYPE_FLOAT3,     D3DDECLMETHOD_DEFAULT,  D3DDECLUSAGE_NORMAL,    0 },
  122.     { 0, 6 * 4, D3DDECLTYPE_FLOAT2,     D3DDECLMETHOD_DEFAULT,  D3DDECLUSAGE_TEXCOORD,  0 },
  123.     D3DDECL_END()
  124. };
  125.  
  126.  
  127. //--------------------------------------------------------------------------------------
  128. // UI control IDs
  129. //--------------------------------------------------------------------------------------
  130. #define IDC_TOGGLEFULLSCREEN    1
  131. #define IDC_TOGGLEREF           3
  132. #define IDC_CHANGEDEVICE        4
  133. #define IDC_NUMBERBOXES_STATIC  5
  134. #define IDC_NUMBERBOXES_SLIDER  6
  135. #define IDC_RENDERMETHOD_LIST   7
  136. #define IDC_BIND_CPU_STATIC     8
  137. #define IDC_BIND_CPU_SLIDER     9
  138. #define IDC_STATIC              10
  139. #define IDC_CPUUSAGE_STATIC     11
  140.  
  141.  
  142. //--------------------------------------------------------------------------------------
  143. // Forward declarations 
  144. //--------------------------------------------------------------------------------------
  145. bool    CALLBACK IsDeviceAcceptable( D3DCAPS9* pCaps, D3DFORMAT AdapterFormat, D3DFORMAT BackBufferFormat, bool bWindowed );
  146. void    CALLBACK ModifyDeviceSettings( DXUTDeviceSettings* pDeviceSettings, const D3DCAPS9* pCaps );
  147. HRESULT CALLBACK OnCreateDevice( IDirect3DDevice9* pd3dDevice, const D3DSURFACE_DESC* pBackBufferSurfaceDesc );
  148. HRESULT CALLBACK OnResetDevice( IDirect3DDevice9* pd3dDevice, const D3DSURFACE_DESC* pBackBufferSurfaceDesc );
  149. void    CALLBACK OnFrameMove( IDirect3DDevice9* pd3dDevice, double fTime, float fElapsedTime );
  150. void    CALLBACK OnFrameRender( IDirect3DDevice9* pd3dDevice, double fTime, float fElapsedTime );
  151. LRESULT CALLBACK MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, bool* pbNoFurtherProcessing );
  152. void    CALLBACK KeyboardProc( UINT nChar, bool bKeyDown, bool bAltDown  );
  153. void    CALLBACK OnGUIEvent( UINT nEvent, int nControlID, CDXUTControl* pControl );
  154. void    CALLBACK OnLostDevice();
  155. void    CALLBACK OnDestroyDevice();
  156. void    CALLBACK OnTimer( UINT idEvent );
  157.  
  158. void    InitApp();
  159. void    RenderText();
  160. HRESULT OnCreateBuffers( IDirect3DDevice9* pd3dDevice );
  161. void    OnDestroyBuffers();
  162.  
  163.  
  164. //--------------------------------------------------------------------------------------
  165. // Entry point to the program. Initializes everything and goes into a message processing 
  166. // loop. Idle time is used to render the scene.
  167. //--------------------------------------------------------------------------------------
  168. INT WINAPI WinMain( HINSTANCE, HINSTANCE, LPSTR, int )
  169. {
  170.     // Set the callback functions. These functions allow the sample framework to notify
  171.     // the application about device changes, user input, and windows messages.  The 
  172.     // callbacks are optional so you need only set callbacks for events you're interested 
  173.     // in. However, if you don't handle the device reset/lost callbacks then the sample 
  174.     // framework won't be able to reset your device since the application must first 
  175.     // release all device resources before resetting.  Likewise, if you don't handle the 
  176.     // device created/destroyed callbacks then the sample framework won't be able to 
  177.     // recreate your device resources.
  178.     DXUTSetCallbackDeviceCreated( OnCreateDevice );
  179.     DXUTSetCallbackDeviceReset( OnResetDevice );
  180.     DXUTSetCallbackDeviceLost( OnLostDevice );
  181.     DXUTSetCallbackDeviceDestroyed( OnDestroyDevice );
  182.     DXUTSetCallbackMsgProc( MsgProc );
  183.     DXUTSetCallbackKeyboard( KeyboardProc );
  184.     DXUTSetCallbackFrameRender( OnFrameRender );
  185.     DXUTSetCallbackFrameMove( OnFrameMove );
  186.     DXUTSetTimer( OnTimer, (float)g_fBurnInterval, NULL );
  187.  
  188.     // Show the cursor and clip it when in full screen
  189.     DXUTSetCursorSettings( true, true );
  190.  
  191.     InitApp();
  192.  
  193.     // Initialize the sample framework and create the desired Win32 window and Direct3D 
  194.     // device for the application. Calling each of these functions is optional, but they
  195.     // allow you to set several options which control the behavior of the framework.
  196.     DXUTInit( true, true, true ); // Parse the command line, handle the default hotkeys, and show msgboxes
  197.     DXUTCreateWindow( L"Instancing" );
  198.     DXUTCreateDevice( D3DADAPTER_DEFAULT, true, 640, 480, IsDeviceAcceptable, ModifyDeviceSettings );
  199.     
  200.     // Performance observations should not be compared against dis-similar builds (debug v retail)
  201. #if defined(DEBUG) | defined(_DEBUG)
  202.     g_bAppIsDebug = true;
  203. #endif
  204.     
  205.     // Performance observations should not be compared against dis-similar d3d runtimes (debug v retail)
  206.     if( GetModuleHandleW( L"d3d9d.dll" ) )
  207.         g_bRuntimeDebug = true;
  208.  
  209.     // Pass control to the sample framework for handling the message pump and 
  210.     // dispatching render calls. The sample framework will call your FrameMove 
  211.     // and FrameRender callback when there is idle time between handling window messages.
  212.     DXUTMainLoop();
  213.     
  214.     // Perform any application-level cleanup here. Direct3D device resources are released within the
  215.     // appropriate callback functions and therefore don't require any cleanup code here.
  216.     
  217.     return DXUTGetExitCode();
  218. }
  219.  
  220.  
  221. //--------------------------------------------------------------------------------------
  222. // Initialize the app 
  223. //--------------------------------------------------------------------------------------
  224. void InitApp()
  225. {
  226.     // Initialize dialogs
  227.     g_HUD.SetCallback( OnGUIEvent ); int iY = 10; 
  228.     g_HUD.AddButton( IDC_TOGGLEFULLSCREEN, L"Toggle full screen", 35, iY, 125, 22 );
  229.     g_HUD.AddButton( IDC_TOGGLEREF, L"Toggle REF (F3)", 35, iY += 24, 125, 22 );
  230.     g_HUD.AddButton( IDC_CHANGEDEVICE, L"Change device (F2)", 35, iY += 24, 125, 22 );
  231.  
  232.     WCHAR szMessage[300];
  233.     g_SampleUI.SetCallback( OnGUIEvent ); iY = 0;
  234.     g_SampleUI2.SetCallback( OnGUIEvent ); iY = 0;
  235.  
  236.     _snwprintf( szMessage, 100, L"# Boxes: %d", g_NumBoxes ); szMessage[99] = 0;
  237.     g_SampleUI.AddStatic( IDC_NUMBERBOXES_STATIC, szMessage, 0, iY += 24, 200, 22 );
  238.     g_SampleUI.AddSlider( IDC_NUMBERBOXES_SLIDER, 50, iY += 24, 100, 22, 1, g_nMaxBoxes, g_NumBoxes );
  239.  
  240.     iY += 24;
  241.     _snwprintf( szMessage, 100, L"Goal: 0ms/frame" ); szMessage[99] = 0;
  242.     g_SampleUI.AddStatic( IDC_BIND_CPU_STATIC, szMessage, 0, iY += 12, 200, 22 );
  243.     wcscpy( szMessage, L"Remaining for logic: 0" );
  244.     g_SampleUI.AddStatic( IDC_CPUUSAGE_STATIC, szMessage, 0, iY += 18, 200, 22 );
  245.     g_SampleUI.AddSlider( IDC_BIND_CPU_SLIDER, 50, iY += 24, 100, 22, 0, 300, g_nBurnCPU );
  246.  
  247.  
  248.     wcscpy( szMessage, L"If rendering takes less\n"
  249.                        L"time than goal, then remaining\n"
  250.                        L"time is spent to represent\n"
  251.                        L"game logic. More time\n"
  252.                        L"remaining means technique\n"
  253.                        L"takes less CPU time\n" );
  254.     g_SampleUI.AddStatic( IDC_STATIC, szMessage, 10, iY += 12*3, 170, 100 );
  255.  
  256.     g_SampleUI2.AddComboBox( IDC_RENDERMETHOD_LIST, 0, 0, 166, 22 );
  257.     g_SampleUI2.GetComboBox( IDC_RENDERMETHOD_LIST )->SetDropHeight( 12*4 );
  258.     g_SampleUI2.GetComboBox( IDC_RENDERMETHOD_LIST )->AddItem( L"Hardware Instancing", NULL );
  259.     g_SampleUI2.GetComboBox( IDC_RENDERMETHOD_LIST )->AddItem( L"Shader Instancing", NULL );
  260.     g_SampleUI2.GetComboBox( IDC_RENDERMETHOD_LIST )->AddItem( L"Constants Instancing", NULL );
  261.     g_SampleUI2.GetComboBox( IDC_RENDERMETHOD_LIST )->AddItem( L"Stream Instancing", NULL );
  262.     g_SampleUI2.GetComboBox( IDC_RENDERMETHOD_LIST )->SetSelectedByIndex( g_iRenderTechnique );
  263.  
  264.     g_SampleUI.EnableKeyboardInput( true );
  265.     g_SampleUI.FocusDefaultControl();
  266. }
  267.  
  268.  
  269. //--------------------------------------------------------------------------------------
  270. // Receives timer callbacks
  271. //--------------------------------------------------------------------------------------
  272. void CALLBACK OnTimer( UINT idEvent )
  273. {
  274. }
  275.  
  276.  
  277. //--------------------------------------------------------------------------------------
  278. // Called during device initialization, this code checks the device for some 
  279. // minimum set of capabilities, and rejects those that don't pass by returning false.
  280. //--------------------------------------------------------------------------------------
  281. bool CALLBACK IsDeviceAcceptable( D3DCAPS9* pCaps, D3DFORMAT AdapterFormat, 
  282.                                   D3DFORMAT BackBufferFormat, bool bWindowed )
  283. {
  284.     // Skip backbuffer formats that don't support alpha blending
  285.     IDirect3D9* pD3D = DXUTGetD3DObject(); 
  286.     if( FAILED( pD3D->CheckDeviceFormat( pCaps->AdapterOrdinal, pCaps->DeviceType,
  287.                     AdapterFormat, D3DUSAGE_QUERY_POSTPIXELSHADER_BLENDING, 
  288.                     D3DRTYPE_TEXTURE, BackBufferFormat ) ) )
  289.         return false;
  290.  
  291.     // Needs PS 1.1 support
  292.     if( pCaps->PixelShaderVersion < D3DPS_VERSION(1,1) )
  293.         return false;
  294.  
  295.     // Needs to be DDI9 (support vertex buffer offset)
  296.     if( !( pCaps->DevCaps2 & D3DDEVCAPS2_STREAMOFFSET ) )
  297.         return false;
  298.     
  299.     return true;
  300. }
  301.  
  302.  
  303. //--------------------------------------------------------------------------------------
  304. // This callback function is called immediately before a device is created to allow the 
  305. // application to modify the device settings. The supplied pDeviceSettings parameter 
  306. // contains the settings that the framework has selected for the new device, and the 
  307. // application can make any desired changes directly to this structure.  Note however that 
  308. // the sample framework will not correct invalid device settings so care must be taken 
  309. // to return valid device settings, otherwise IDirect3D9::CreateDevice() will fail.  
  310. //--------------------------------------------------------------------------------------
  311. void CALLBACK ModifyDeviceSettings( DXUTDeviceSettings* pDeviceSettings, const D3DCAPS9* pCaps )
  312. {
  313.     // If device doesn't support HW T&L or doesn't support 2.0 vertex shaders in HW 
  314.     // then switch to SWVP.
  315.     if( (pCaps->DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) == 0 ||
  316.          pCaps->VertexShaderVersion < D3DVS_VERSION(2,0) )
  317.     {
  318.         pDeviceSettings->BehaviorFlags = D3DCREATE_SOFTWARE_VERTEXPROCESSING;
  319.     }
  320.     else
  321.     {
  322.         pDeviceSettings->BehaviorFlags = D3DCREATE_HARDWARE_VERTEXPROCESSING;
  323.     }
  324.  
  325.     // This application is designed to work on a pure device by not using 
  326.     // IDirect3D9::Get*() methods, so create a pure device if supported and using HWVP.
  327.     if ((pCaps->DevCaps & D3DDEVCAPS_PUREDEVICE) != 0 && 
  328.         (pDeviceSettings->BehaviorFlags & D3DCREATE_HARDWARE_VERTEXPROCESSING) != 0 )
  329.         pDeviceSettings->BehaviorFlags |= D3DCREATE_PUREDEVICE;
  330.  
  331.     // Debugging vertex shaders requires either REF or software vertex processing 
  332.     // and debugging pixel shaders requires REF.  
  333. #ifdef DEBUG_PS
  334.     pDeviceSettings->DeviceType = D3DDEVTYPE_REF;
  335. #endif
  336. #ifdef DEBUG_VS
  337.     if( pDeviceSettings->DeviceType != D3DDEVTYPE_REF )
  338.     {
  339.         pDeviceSettings->BehaviorFlags &= ~D3DCREATE_HARDWARE_VERTEXPROCESSING;
  340.         pDeviceSettings->BehaviorFlags &= ~D3DCREATE_MIXED_VERTEXPROCESSING;
  341.         pDeviceSettings->BehaviorFlags &= ~D3DCREATE_PUREDEVICE;                            
  342.         pDeviceSettings->BehaviorFlags |= D3DCREATE_SOFTWARE_VERTEXPROCESSING;
  343.     }
  344. #endif
  345.  
  346.     if (pDeviceSettings->pp.Windowed == FALSE)
  347.         pDeviceSettings->pp.SwapEffect = D3DSWAPEFFECT_FLIP;
  348. }
  349.  
  350. //--------------------------------------------------------------------------------------
  351. // Helper routine to fill faces of a cube
  352. //--------------------------------------------------------------------------------------
  353. void FillFace(
  354.     BOX_VERTEX *pVerts, 
  355.     WORD *pIndices, 
  356.     int iFace,
  357.     D3DXVECTOR3 vCenter, 
  358.     D3DXVECTOR3 vNormal, 
  359.     D3DXVECTOR3 vUp )
  360. {
  361.     D3DXVECTOR3 vRight;
  362.     D3DXVec3Cross(&vRight, &vNormal, &vUp);
  363.  
  364.     pIndices[ iFace * 6 + 0 ] = iFace * 4 + 0;
  365.     pIndices[ iFace * 6 + 1 ] = iFace * 4 + 1;
  366.     pIndices[ iFace * 6 + 2 ] = iFace * 4 + 2;
  367.     pIndices[ iFace * 6 + 3 ] = iFace * 4 + 3;
  368.     pIndices[ iFace * 6 + 4 ] = iFace * 4 + 2;
  369.     pIndices[ iFace * 6 + 5 ] = iFace * 4 + 1;
  370.  
  371.     pVerts[ iFace * 4 + 0 ].pos = vCenter + vRight + vUp;
  372.     pVerts[ iFace * 4 + 1 ].pos = vCenter + vRight - vUp;
  373.     pVerts[ iFace * 4 + 2 ].pos = vCenter - vRight + vUp;
  374.     pVerts[ iFace * 4 + 3 ].pos = vCenter - vRight - vUp;
  375.  
  376.     for( int i = 0; i < 4; i++ )
  377.     {
  378.         pVerts[ iFace * 4 + i ].u =(float)( ( i / 2 ) & 1 ) * 1.0f;
  379.         pVerts[ iFace * 4 + i ].v =(float)( ( i ) & 1 ) * 1.0f;
  380.         pVerts[ iFace * 4 + i ].norm = vNormal;
  381.     }
  382. }
  383.  
  384.  
  385. //--------------------------------------------------------------------------------------
  386. // Helper routine to fill faces of a cube + instance data
  387. //--------------------------------------------------------------------------------------
  388. void FillFaceInstance(
  389.     BOX_VERTEX_INSTANCE *pVerts, 
  390.     WORD *pIndices, 
  391.     int iFace,
  392.     D3DXVECTOR3 vCenter, 
  393.     D3DXVECTOR3 vNormal, 
  394.     D3DXVECTOR3 vUp,
  395.     WORD iInstanceIndex )
  396. {
  397.     D3DXVECTOR3 vRight;
  398.     D3DXVec3Cross(&vRight, &vNormal, &vUp);
  399.     
  400.     WORD offsetIndex = iInstanceIndex * 6 * 2 * 3;  // offset from the beginning of the index array
  401.     WORD offsetVertex = iInstanceIndex * 4 * 6;     // offset from the beginning of the vertex array
  402.  
  403.     pIndices[ offsetIndex + iFace * 6 + 0 ] = offsetVertex + iFace * 4 + 0;
  404.     pIndices[ offsetIndex + iFace * 6 + 1 ] = offsetVertex + iFace * 4 + 1;
  405.     pIndices[ offsetIndex + iFace * 6 + 2 ] = offsetVertex + iFace * 4 + 2;
  406.     pIndices[ offsetIndex + iFace * 6 + 3 ] = offsetVertex + iFace * 4 + 3;
  407.     pIndices[ offsetIndex + iFace * 6 + 4 ] = offsetVertex + iFace * 4 + 2;
  408.     pIndices[ offsetIndex + iFace * 6 + 5 ] = offsetVertex + iFace * 4 + 1;
  409.  
  410.     pVerts[ offsetVertex + iFace * 4 + 0 ].pos = vCenter + vRight + vUp;
  411.     pVerts[ offsetVertex + iFace * 4 + 1 ].pos = vCenter + vRight - vUp;
  412.     pVerts[ offsetVertex + iFace * 4 + 2 ].pos = vCenter - vRight + vUp;
  413.     pVerts[ offsetVertex + iFace * 4 + 3 ].pos = vCenter - vRight - vUp;
  414.  
  415.     for( int i = 0; i < 4; i++ )
  416.     {
  417.         pVerts[ offsetVertex + iFace * 4 + i ].boxInstance = (float)iInstanceIndex;
  418.         pVerts[ offsetVertex + iFace * 4 + i ].u =(float)( ( i / 2 ) & 1 ) * 1.0f;
  419.         pVerts[ offsetVertex + iFace * 4 + i ].v =(float)( ( i ) & 1 ) * 1.0f;
  420.         pVerts[ offsetVertex + iFace * 4 + i ].norm = vNormal;
  421.     }
  422. }
  423.  
  424.  
  425. //--------------------------------------------------------------------------------------
  426. // Create the vertex and index buffers, based on the selected instancing method
  427. // called from onCreateDevice or whenever user changes parameters or rendering method
  428. //--------------------------------------------------------------------------------------
  429. HRESULT OnCreateBuffers( IDirect3DDevice9* pd3dDevice )
  430. {
  431.     HRESULT hr;
  432.  
  433.     if( 0 == g_iRenderTechnique || 3 == g_iRenderTechnique )
  434.     {
  435.         g_HandleTechnique = g_pEffect->GetTechniqueByName( "THW_Instancing" );
  436.  
  437.         // Create the vertex declaration
  438.         V_RETURN( pd3dDevice->CreateVertexDeclaration( g_VertexElemHardware, &g_pVertexDeclHardware ) );
  439.     }
  440.  
  441.     if( 1 == g_iRenderTechnique )
  442.     {
  443.         g_HandleTechnique = g_pEffect->GetTechniqueByName( "TShader_Instancing" );
  444.         g_HandleBoxInstance_Position = g_pEffect->GetParameterBySemantic( NULL, "BOXINSTANCEARRAY_POSITION" );
  445.         g_HandleBoxInstance_Color = g_pEffect->GetParameterBySemantic( NULL, "BOXINSTANCEARRAY_COLOR" );
  446.  
  447.         // First create the vertex declaration we need
  448.         V_RETURN( pd3dDevice->CreateVertexDeclaration( g_VertexElemShader, &g_pVertexDeclShader ) );
  449.     
  450.         // Build a VB to hold the position data. Four vertices on six faces of the box
  451.         // Create g_nNumBatchInstance copies
  452.         V_RETURN( pd3dDevice->CreateVertexBuffer( g_nNumBatchInstance * 4 * 6 * sizeof( BOX_VERTEX_INSTANCE ), 0, 0, D3DPOOL_MANAGED, & g_pVBBox, 0 ) );
  453.  
  454.         // And an IB to go with it. We will be rendering
  455.         // a list of independent tris, and each box face has two tris, so the box will have
  456.         // 6 * 2 * 3 indices
  457.         V_RETURN( pd3dDevice->CreateIndexBuffer( g_nNumBatchInstance * ( 6 * 2 * 3 ) * sizeof( WORD ), 0, D3DFMT_INDEX16, D3DPOOL_MANAGED, &g_pIBBox, 0 ) );
  458.     
  459.         // Now, lock and fill the model VB and IB
  460.         BOX_VERTEX_INSTANCE *pVerts;
  461.  
  462.         hr = g_pVBBox->Lock( 0, NULL, (void**) &pVerts, 0 );
  463.  
  464.         if( SUCCEEDED( hr ) )
  465.         {
  466.             WORD * pIndices;
  467.             hr = g_pIBBox->Lock( 0, NULL, (void**) &pIndices, 0 );
  468.         
  469.             if( SUCCEEDED( hr ) )
  470.             {
  471.                 for( WORD iInstance = 0; iInstance < g_nNumBatchInstance; iInstance++ )
  472.                 {
  473.                     FillFaceInstance( pVerts, pIndices, 0,
  474.                         D3DXVECTOR3( 0.f, 0.f,-1.f),
  475.                         D3DXVECTOR3( 0.f, 0.f,-1.f),
  476.                         D3DXVECTOR3( 0.f, 1.f, 0.f),
  477.                         iInstance );
  478.  
  479.                     FillFaceInstance( pVerts, pIndices, 1,
  480.                         D3DXVECTOR3( 0.f, 0.f, 1.f),
  481.                         D3DXVECTOR3( 0.f, 0.f, 1.f),
  482.                         D3DXVECTOR3( 0.f, 1.f, 0.f),
  483.                         iInstance );
  484.  
  485.                     FillFaceInstance( pVerts, pIndices,2,
  486.                         D3DXVECTOR3( 1.f, 0.f, 0.f),
  487.                         D3DXVECTOR3( 1.f, 0.f, 0.f),
  488.                         D3DXVECTOR3( 0.f, 1.f, 0.f),
  489.                         iInstance );
  490.  
  491.                     FillFaceInstance( pVerts, pIndices,3,
  492.                         D3DXVECTOR3(-1.f, 0.f, 0.f),
  493.                         D3DXVECTOR3(-1.f, 0.f, 0.f),
  494.                         D3DXVECTOR3( 0.f, 1.f, 0.f),
  495.                         iInstance );
  496.  
  497.                     FillFaceInstance( pVerts, pIndices,4,
  498.                         D3DXVECTOR3( 0.f, 1.f, 0.f),
  499.                         D3DXVECTOR3( 0.f, 1.f, 0.f),
  500.                         D3DXVECTOR3( 1.f, 0.f, 0.f),
  501.                         iInstance );
  502.  
  503.                     FillFaceInstance( pVerts, pIndices,5,
  504.                         D3DXVECTOR3( 0.f,-1.f, 0.f),
  505.                         D3DXVECTOR3( 0.f,-1.f, 0.f),
  506.                         D3DXVECTOR3( 1.f, 0.f, 0.f),
  507.                         iInstance );
  508.                 }
  509.  
  510.                 g_pIBBox->Unlock();
  511.             }
  512.             else
  513.             {
  514.                 DXUT_ERR(L"Could not lock box model IB", hr);
  515.             }
  516.             g_pVBBox->Unlock();
  517.         }
  518.         else
  519.         {
  520.             DXUT_ERR(L"Could not lock box model VB", hr);
  521.         }
  522.     }
  523.         
  524.     if( 2 == g_iRenderTechnique )
  525.     {
  526.         g_HandleTechnique = g_pEffect->GetTechniqueByName( "TConstants_Instancing" );
  527.         g_HandleBoxInstance_Position = g_pEffect->GetParameterBySemantic( NULL, "BOXINSTANCE_POSITION" );
  528.         g_HandleBoxInstance_Color = g_pEffect->GetParameterBySemantic( NULL, "BOXINSTANCE_COLOR" );
  529.  
  530.         // Create the vertex declaration
  531.         V_RETURN( pd3dDevice->CreateVertexDeclaration( g_VertexElemConstants, &g_pVertexDeclConstants ) );
  532.     }
  533.  
  534.     if( 1 != g_iRenderTechnique )
  535.     {
  536.         // Build a VB to hold the position data. Four vertices on six faces of the box
  537.         V_RETURN( pd3dDevice->CreateVertexBuffer( 4 * 6 * sizeof( BOX_VERTEX ), 0, 0, D3DPOOL_MANAGED, & g_pVBBox, 0 ) );
  538.  
  539.         // And an IB to go with it. We will be rendering
  540.         // a list of independent tris, and each box face has two tris, so the box will have
  541.         // 6 * 2 * 3 indices
  542.         V_RETURN( pd3dDevice->CreateIndexBuffer( ( 6 * 2 * 3 ) * sizeof( WORD ), 0, D3DFMT_INDEX16, D3DPOOL_MANAGED, &g_pIBBox, 0 ) );
  543.     
  544.         // Now, lock and fill the model VB and IB:
  545.         BOX_VERTEX * pVerts;
  546.  
  547.         hr = g_pVBBox->Lock( 0, NULL, (void**) &pVerts, 0 );
  548.  
  549.         if( SUCCEEDED( hr ) )
  550.         {
  551.             WORD * pIndices;
  552.             hr = g_pIBBox->Lock( 0, NULL, (void**) &pIndices, 0 );
  553.         
  554.             if( SUCCEEDED( hr ) )
  555.             {
  556.                 FillFace( pVerts, pIndices, 0,
  557.                     D3DXVECTOR3( 0.f, 0.f,-1.f),
  558.                     D3DXVECTOR3( 0.f, 0.f,-1.f),
  559.                     D3DXVECTOR3( 0.f, 1.f, 0.f) );
  560.  
  561.                 FillFace( pVerts, pIndices, 1,
  562.                     D3DXVECTOR3( 0.f, 0.f, 1.f),
  563.                     D3DXVECTOR3( 0.f, 0.f, 1.f),
  564.                     D3DXVECTOR3( 0.f, 1.f, 0.f) );
  565.  
  566.                 FillFace( pVerts, pIndices,2,
  567.                     D3DXVECTOR3( 1.f, 0.f, 0.f),
  568.                     D3DXVECTOR3( 1.f, 0.f, 0.f),
  569.                     D3DXVECTOR3( 0.f, 1.f, 0.f) );
  570.  
  571.                 FillFace( pVerts, pIndices,3,
  572.                     D3DXVECTOR3(-1.f, 0.f, 0.f),
  573.                     D3DXVECTOR3(-1.f, 0.f, 0.f),
  574.                     D3DXVECTOR3( 0.f, 1.f, 0.f) );
  575.  
  576.                 FillFace( pVerts, pIndices,4,
  577.                     D3DXVECTOR3( 0.f, 1.f, 0.f),
  578.                     D3DXVECTOR3( 0.f, 1.f, 0.f),
  579.                     D3DXVECTOR3( 1.f, 0.f, 0.f) );
  580.  
  581.                 FillFace( pVerts, pIndices,5,
  582.                     D3DXVECTOR3( 0.f,-1.f, 0.f),
  583.                     D3DXVECTOR3( 0.f,-1.f, 0.f),
  584.                     D3DXVECTOR3( 1.f, 0.f, 0.f) );
  585.  
  586.                 g_pIBBox->Unlock();
  587.             }
  588.             else
  589.             {
  590.                 DXUT_ERR(L"Could not lock box model IB", hr);
  591.             }
  592.             g_pVBBox->Unlock();
  593.         }
  594.         else
  595.         {
  596.             DXUT_ERR(L"Could not lock box model VB", hr);
  597.         }
  598.     }
  599.  
  600.     if( 0 == g_iRenderTechnique || 3 == g_iRenderTechnique )
  601.     {
  602.         // Create a  VB for the instancing data
  603.         V_RETURN( pd3dDevice->CreateVertexBuffer( g_NumBoxes * sizeof( BOX_INSTANCEDATA_POS ), 0, 0, D3DPOOL_MANAGED, &g_pVBInstanceData, 0 ) );
  604.         
  605.         // Lock and fill the instancing buffer
  606.         BOX_INSTANCEDATA_POS *pIPos;
  607.         hr = g_pVBInstanceData->Lock( 0, NULL,  (void**) &pIPos, 0 );
  608.         
  609.         if( SUCCEEDED( hr ) )
  610.         {
  611.             int nRemainingBoxes = g_NumBoxes;
  612.             for( BYTE iY = 0; iY < 10; iY++ )
  613.                 for( BYTE iZ = 0; iZ < 10; iZ++ )
  614.                     for( BYTE iX = 0; iX < 10 && nRemainingBoxes > 0; iX++, nRemainingBoxes-- )
  615.                     {
  616.                         // Scaled so 1 box is "32" wide, the intra-pos range is 8 box widths.
  617.                         // The positins are scaled and biased.
  618.                         // The rotations are not
  619.                         BOX_INSTANCEDATA_POS instanceBox;
  620.                         instanceBox.color = D3DCOLOR_ARGB( 0xff, 0x7f + 0x40 * ((g_NumBoxes - nRemainingBoxes + iX) % 3), 0x7f + 0x40 * ((g_NumBoxes - nRemainingBoxes+iZ+1) % 3), 0x7f + 0x40 * ((g_NumBoxes - nRemainingBoxes+iY+2) % 3) );
  621.                         instanceBox.x = iZ * 24;
  622.                         instanceBox.z = iX * 24;
  623.                         instanceBox.y = iY * 24;
  624.                         instanceBox.rotation = ((WORD)iX + (WORD)iZ + (WORD)iY) * 24 / 3;
  625.                         *pIPos = instanceBox, pIPos++;
  626.                     }
  627.             g_pVBInstanceData->Unlock();
  628.         }
  629.         else
  630.         {
  631.             DXUT_ERR(L"Could not lock box intra-pile-position VB", hr);
  632.         }
  633.     }
  634.  
  635.     if( 1 == g_iRenderTechnique || 2 == g_iRenderTechnique )
  636.     {
  637.         // Fill the instancing constants buffer
  638.         int nRemainingBoxes = g_NumBoxes;
  639.         for( BYTE iY = 0; iY < 10; iY++ )
  640.             for( BYTE iZ = 0; iZ < 10; iZ++ )
  641.                 for( BYTE iX = 0; iX < 10 && nRemainingBoxes > 0; iX++, nRemainingBoxes-- )
  642.                 {
  643.                     // Scaled so 1 box is "32" wide, the intra-pos range is 8 box widths.
  644.                     // The positins are scaled and biased.
  645.                     // The rotations are not
  646.                     g_vBoxInstance_Color[g_NumBoxes - nRemainingBoxes] = D3DCOLOR_ARGB( 0xff, 0x7f + 0x40 * ((g_NumBoxes - nRemainingBoxes + iX) % 3), 0x7f + 0x40 * ((g_NumBoxes - nRemainingBoxes+iZ+1) % 3), 0x7f + 0x40 * ((g_NumBoxes - nRemainingBoxes+iY+2) % 3) );
  647.                     g_vBoxInstance_Position[g_NumBoxes - nRemainingBoxes].x = iX * 24 / 255.0f;
  648.                     g_vBoxInstance_Position[g_NumBoxes - nRemainingBoxes].z = iZ * 24 / 255.0f;
  649.                     g_vBoxInstance_Position[g_NumBoxes - nRemainingBoxes].y = iY * 24 / 255.0f;
  650.                     g_vBoxInstance_Position[g_NumBoxes - nRemainingBoxes].w = ((WORD)iX + (WORD)iZ + (WORD)iY) * 8 / 255.0f;
  651.                 }
  652.     }   
  653.  
  654.     return S_OK;
  655. }
  656.  
  657.  
  658. //--------------------------------------------------------------------------------------
  659. // Release the vertex and index buffers, based on the selected instancing method
  660. // called from onDestroyDevice or whenever user changes parameters or rendering method
  661. //--------------------------------------------------------------------------------------
  662. void OnDestroyBuffers()
  663. {
  664.     SAFE_RELEASE(g_pVBBox);
  665.     SAFE_RELEASE(g_pIBBox);
  666.     SAFE_RELEASE(g_pVBInstanceData);
  667.     SAFE_RELEASE(g_pVertexDeclHardware);
  668.     SAFE_RELEASE(g_pVertexDeclShader);
  669.     SAFE_RELEASE(g_pVertexDeclConstants);
  670. }
  671.  
  672.  
  673. //--------------------------------------------------------------------------------------
  674. // This callback function will be called immediately after the Direct3D device has been 
  675. // created, which will happen during application initialization and windowed/full screen 
  676. // toggles. This is the best location to create D3DPOOL_MANAGED resources since these 
  677. // resources need to be reloaded whenever the device is destroyed. Resources created  
  678. // here should be released in the OnDestroyDevice callback. 
  679. //--------------------------------------------------------------------------------------
  680. HRESULT CALLBACK OnCreateDevice( IDirect3DDevice9* pd3dDevice, const D3DSURFACE_DESC* pBackBufferSurfaceDesc )
  681. {
  682.     HRESULT hr;
  683.  
  684.     // Initialize the font
  685.     V_RETURN( D3DXCreateFont( pd3dDevice, 15, 0, FW_BOLD, 0, FALSE, DEFAULT_CHARSET, 
  686.                          OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, 
  687.                          L"Arial", &g_pFont ) );
  688.  
  689.     // Define DEBUG_VS and/or DEBUG_PS to debug vertex and/or pixel shaders with the 
  690.     // shader debugger. Debugging vertex shaders requires either REF or software vertex 
  691.     // processing, and debugging pixel shaders requires REF.  The 
  692.     // D3DXSHADER_FORCE_*_SOFTWARE_NOOPT flag improves the debug experience in the 
  693.     // shader debugger.  It enables source level debugging, prevents instruction 
  694.     // reordering, prevents dead code elimination, and forces the compiler to compile 
  695.     // against the next higher available software target, which ensures that the 
  696.     // unoptimized shaders do not exceed the shader model limitations.  Setting these 
  697.     // flags will cause slower rendering since the shaders will be unoptimized and 
  698.     // forced into software.  See the DirectX documentation for more information about 
  699.     // using the shader debugger.
  700.     DWORD dwShaderFlags = 0;
  701.     #ifdef DEBUG_VS
  702.         dwShaderFlags |= D3DXSHADER_FORCE_VS_SOFTWARE_NOOPT;
  703.     #endif
  704.     #ifdef DEBUG_PS
  705.         dwShaderFlags |= D3DXSHADER_FORCE_PS_SOFTWARE_NOOPT;
  706.     #endif
  707.  
  708.     // Read the D3DX effect file
  709.     WCHAR str[MAX_PATH];
  710.     V_RETURN( DXUTFindDXSDKMediaFileCch( str, MAX_PATH, L"Instancing.fx" ) );
  711.  
  712.     // If this fails, there should be debug output as to 
  713.     // they the .fx file failed to compile
  714.     V_RETURN( D3DXCreateEffectFromFile( pd3dDevice, str, NULL, NULL, dwShaderFlags, 
  715.                                         NULL, &g_pEffect, NULL ) );
  716.  
  717.     g_HandleWorld = g_pEffect->GetParameterBySemantic( NULL, "WORLD" );
  718.     g_HandleView = g_pEffect->GetParameterBySemantic( NULL, "VIEW" );
  719.     g_HandleProjection = g_pEffect->GetParameterBySemantic( NULL, "PROJECTION" );
  720.     g_HandleTexture = g_pEffect->GetParameterBySemantic( NULL, "TEXTURE" );
  721.  
  722.     // Setup the camera's view parameters
  723.     D3DXVECTOR3 vecEye( -24.0f, 36.0f, -36.0f );
  724.     D3DXVECTOR3 vecAt ( 0.0f, 0.0f, 0.0f );
  725.     g_Camera.SetViewParams( &vecEye, &vecAt );
  726.  
  727.     // create vertex, index buffers and vertex declaration
  728.     V_RETURN( OnCreateBuffers( pd3dDevice ) );
  729.  
  730.     // Load the environment texture
  731.     hr = DXUTFindDXSDKMediaFileCch( str, MAX_PATH, L"Misc\\env2.bmp" );
  732.     if( FAILED(hr) )
  733.         return DXTRACE_ERR( L"DXUTFindDXSDKMediaFileCch", hr );
  734.     hr = D3DXCreateTextureFromFile( pd3dDevice, str, &g_pBoxTexture );
  735.     if( FAILED( hr ) )
  736.         return DXTRACE_ERR( L"D3DXCreateTextureFromFile", hr );
  737.  
  738.     return S_OK;
  739. }
  740.  
  741.  
  742. //--------------------------------------------------------------------------------------
  743. // This callback function will be called immediately after the Direct3D device has been 
  744. // reset, which will happen after a lost device scenario. This is the best location to 
  745. // create D3DPOOL_DEFAULT resources since these resources need to be reloaded whenever 
  746. // the device is lost. Resources created here should be released in the OnLostDevice 
  747. // callback. 
  748. //--------------------------------------------------------------------------------------
  749. HRESULT CALLBACK OnResetDevice( IDirect3DDevice9* pd3dDevice, 
  750.                                 const D3DSURFACE_DESC* pBackBufferSurfaceDesc )
  751. {
  752.     HRESULT hr;
  753.     
  754.     if( g_pFont )
  755.         V_RETURN( g_pFont->OnResetDevice() );
  756.     if( g_pEffect )
  757.         V_RETURN( g_pEffect->OnResetDevice() );
  758.     
  759.     // Create a sprite to help batch calls when drawing many lines of text
  760.     V_RETURN( D3DXCreateSprite( pd3dDevice, &g_pTextSprite ) );
  761.     
  762.     // Setup the camera's projection parameters
  763.     float fAspectRatio = pBackBufferSurfaceDesc->Width / (FLOAT)pBackBufferSurfaceDesc->Height;
  764.     g_Camera.SetProjParams( D3DX_PI / 3, fAspectRatio, 0.1f, 1000.0f );
  765.     g_Camera.SetWindow( pBackBufferSurfaceDesc->Width, pBackBufferSurfaceDesc->Height );
  766.     
  767.     // Set the camera speed
  768.     g_Camera.SetScalers( 0.01f, 10.0f );
  769.     
  770.     // Constrain the camera to movement within the horizontal plane
  771.     g_Camera.SetEnableYAxisMovement( false );
  772.     g_Camera.SetEnablePositionMovement( true );
  773.     
  774.     g_HUD.SetLocation( pBackBufferSurfaceDesc->Width-170, 0 );
  775.     g_HUD.SetSize( 170, 170 );
  776.     g_SampleUI.SetLocation( pBackBufferSurfaceDesc->Width-170, pBackBufferSurfaceDesc->Height-400 );
  777.     g_SampleUI.SetSize( 170, 400 );
  778.     g_SampleUI2.SetLocation( 0, 100 );
  779.     g_SampleUI2.SetSize( 200, 100 );
  780.     
  781.     return S_OK;
  782. }
  783.  
  784.  
  785. //--------------------------------------------------------------------------------------
  786. // This callback function will be called once at the beginning of every frame. This is the
  787. // best location for your application to handle updates to the scene, but is not 
  788. // intended to contain actual rendering calls, which should instead be placed in the 
  789. // OnFrameRender callback.  
  790. //--------------------------------------------------------------------------------------
  791. void CALLBACK OnFrameMove( IDirect3DDevice9* pd3dDevice, double fTime, float fElapsedTime )
  792. {
  793.     // Burn CPU time       
  794.     WCHAR szMessage[100];
  795.     WCHAR szTmp[100];
  796.     static double s_fLastTime = DXUTGetGlobalTimer()->GetTime();
  797.     double fStartTime = DXUTGetGlobalTimer()->GetTime();
  798.     double fCurTime = fStartTime;
  799.     double fStopTime = s_fLastTime + g_fBurnAmount;
  800.  
  801.     while( fCurTime < fStopTime )
  802.     {
  803.         fCurTime = DXUTGetGlobalTimer()->GetTime();
  804.         double fTmp = fStartTime / s_fLastTime * 100.0f;
  805.         _snwprintf( szTmp, 100, L"Test %d", (int)(fTmp + 0.5f) ); 
  806.     }
  807.  
  808.     double fCPUUsage = (fCurTime - fStartTime) / (fCurTime - s_fLastTime) * 100.0f;
  809.     s_fLastTime = DXUTGetGlobalTimer()->GetTime();
  810.     _snwprintf( szMessage, 100, L"Remaining for logic: %d%%", (int)(fCPUUsage + 0.5f) ); szMessage[99] = 0;
  811.  
  812.     // don't update the message every single time
  813.     if( 0 == g_iUpdateCPUUsageMessage )
  814.         g_SampleUI.GetStatic( IDC_CPUUSAGE_STATIC )->SetText( szMessage );
  815.     g_iUpdateCPUUsageMessage = ( g_iUpdateCPUUsageMessage + 1 ) % 100;
  816.  
  817.     // Update the camera's position based on user input 
  818.     g_Camera.FrameMove( fElapsedTime );
  819. }
  820.  
  821.  
  822. //--------------------------------------------------------------------------------------
  823. // This callback function is called by OnFrameRender
  824. // It performs HW instancing
  825. //--------------------------------------------------------------------------------------
  826. void OnRenderHWInstancing( IDirect3DDevice9* pd3dDevice, double fTime, float fElapsedTime )
  827. {
  828.     HRESULT hr;
  829.     UINT iPass, cPasses;
  830.  
  831.     V( pd3dDevice->SetVertexDeclaration( g_pVertexDeclHardware ));
  832.         
  833.     // Stream zero is our model, and its frequency is how we communicate the number of instances required,
  834.     // which in this case is the total number of boxes
  835.     V( pd3dDevice->SetStreamSource( 0, g_pVBBox, 0, sizeof(BOX_VERTEX)) );
  836.     V( pd3dDevice->SetStreamSourceFreq( 0, D3DSTREAMSOURCE_INDEXEDDATA | g_NumBoxes ) );
  837.         
  838.     // Stream one is the instancing buffer, so this advances to the next value
  839.     // after each box instance has been drawn, so the divider is 1.
  840.     V( pd3dDevice->SetStreamSource( 1, g_pVBInstanceData, 0, sizeof( BOX_INSTANCEDATA_POS ) ) );
  841.     V( pd3dDevice->SetStreamSourceFreq( 1, D3DSTREAMSOURCE_INSTANCEDATA | 1ul ) );
  842.  
  843.     V( pd3dDevice->SetIndices( g_pIBBox ) );
  844.         
  845.     // Render the scene with this technique
  846.     // as defined in the .fx file
  847.     V( g_pEffect->SetTechnique( g_HandleTechnique ) );
  848.         
  849.     V( g_pEffect->Begin( &cPasses, 0 ) );
  850.     for( iPass = 0; iPass < cPasses; iPass++ )
  851.     {
  852.         V( g_pEffect->BeginPass( iPass ) );
  853.             
  854.         // Render the boxes with the applied technique
  855.         V( g_pEffect->SetTexture( g_HandleTexture, g_pBoxTexture ) );
  856.             
  857.         // The effect interface queues up the changes and performs them 
  858.         // with the CommitChanges call. You do not need to call CommitChanges if 
  859.         // you are not setting any parameters between the BeginPass and EndPass.
  860.         V( g_pEffect->CommitChanges() );
  861.             
  862.         V( pd3dDevice->DrawIndexedPrimitive( D3DPT_TRIANGLELIST, 0, 0, 4 * 6, 0, 6 * 2 ) );
  863.             
  864.         V( g_pEffect->EndPass() );
  865.     }
  866.     V( g_pEffect->End() );
  867.         
  868.     V( pd3dDevice->SetStreamSourceFreq( 0, 1 ) );
  869.     V( pd3dDevice->SetStreamSourceFreq( 1, 1 ) );
  870. }
  871.  
  872.  
  873. //--------------------------------------------------------------------------------------
  874. // This callback function is called by OnFrameRender
  875. // It performs Shader instancing
  876. //--------------------------------------------------------------------------------------
  877. void OnRenderShaderInstancing( IDirect3DDevice9* pd3dDevice, double fTime, float fElapsedTime )
  878. {
  879.     HRESULT hr;
  880.     UINT iPass, cPasses;
  881.  
  882.     V( pd3dDevice->SetVertexDeclaration( g_pVertexDeclShader ));
  883.         
  884.     // Stream zero is our model
  885.     V( pd3dDevice->SetStreamSource( 0, g_pVBBox, 0, sizeof( BOX_VERTEX_INSTANCE ) ) );
  886.     V( pd3dDevice->SetIndices( g_pIBBox ) );
  887.         
  888.     // Render the scene with this technique
  889.     // as defined in the .fx file
  890.     V( g_pEffect->SetTechnique( g_HandleTechnique ) );
  891.         
  892.     V( g_pEffect->Begin( &cPasses, 0 ) );
  893.     for( iPass = 0; iPass < cPasses; iPass++ )
  894.     {
  895.         V( g_pEffect->BeginPass( iPass ) );
  896.             
  897.         // Render the boxes with the applied technique
  898.         V( g_pEffect->SetTexture( g_HandleTexture, g_pBoxTexture ) );
  899.  
  900.         int nRemainingBoxes = g_NumBoxes;
  901.         while( nRemainingBoxes > 0 )
  902.         {
  903.             // determine how many instances are in this batch (up to g_nNumBatchInstance)           
  904.             int nRenderBoxes = min( nRemainingBoxes, g_nNumBatchInstance );
  905.  
  906.             // set the box instancing array
  907.             V( g_pEffect->SetVectorArray( g_HandleBoxInstance_Position, g_vBoxInstance_Position + g_NumBoxes - nRemainingBoxes, nRenderBoxes) );
  908.             V( g_pEffect->SetVectorArray( g_HandleBoxInstance_Color, (D3DXVECTOR4*)(g_vBoxInstance_Color + g_NumBoxes - nRemainingBoxes), nRenderBoxes) );
  909.             
  910.             // The effect interface queues up the changes and performs them 
  911.             // with the CommitChanges call. You do not need to call CommitChanges if 
  912.             // you are not setting any parameters between the BeginPass and EndPass.
  913.             V( g_pEffect->CommitChanges() );
  914.             
  915.             V( pd3dDevice->DrawIndexedPrimitive( D3DPT_TRIANGLELIST, 0, 0, nRenderBoxes * 4 * 6, 0, nRenderBoxes * 6 * 2 ) );
  916.  
  917.             // subtract the rendered boxes from the remaining boxes
  918.             nRemainingBoxes -= nRenderBoxes;
  919.         }
  920.  
  921.         V( g_pEffect->EndPass() );
  922.     }
  923.     V( g_pEffect->End() );
  924. }
  925.  
  926.  
  927. //--------------------------------------------------------------------------------------
  928. // This callback function is called by OnFrameRender
  929. // It performs Constants instancing
  930. //--------------------------------------------------------------------------------------
  931. void OnRenderConstantsInstancing( IDirect3DDevice9* pd3dDevice, double fTime, float fElapsedTime )
  932. {
  933.     HRESULT hr;
  934.     UINT iPass, cPasses;
  935.  
  936.     V( pd3dDevice->SetVertexDeclaration( g_pVertexDeclConstants ));
  937.         
  938.     // Stream zero is our model
  939.     V( pd3dDevice->SetStreamSource( 0, g_pVBBox, 0, sizeof( BOX_VERTEX ) ) );
  940.     V( pd3dDevice->SetIndices( g_pIBBox ) );
  941.  
  942.     // Render the scene with this technique
  943.     // as defined in the .fx file
  944.     V( g_pEffect->SetTechnique( g_HandleTechnique ) );
  945.         
  946.     V( g_pEffect->Begin( &cPasses, 0 ) );
  947.     for( iPass = 0; iPass < cPasses; iPass++ )
  948.     {
  949.         V( g_pEffect->BeginPass( iPass ) );
  950.             
  951.         // Render the boxes with the applied technique
  952.         V( g_pEffect->SetTexture( g_HandleTexture, g_pBoxTexture ) );
  953.  
  954.         for( int nRemainingBoxes = 0; nRemainingBoxes < g_NumBoxes; nRemainingBoxes++ )
  955.         {
  956.             // set the box instancing array
  957.             V( g_pEffect->SetVector( g_HandleBoxInstance_Position, &g_vBoxInstance_Position[nRemainingBoxes] ) );
  958.             V( g_pEffect->SetVector( g_HandleBoxInstance_Color, (D3DXVECTOR4*)&g_vBoxInstance_Color[nRemainingBoxes] ) );
  959.             
  960.             // The effect interface queues up the changes and performs them 
  961.             // with the CommitChanges call. You do not need to call CommitChanges if 
  962.             // you are not setting any parameters between the BeginPass and EndPass.
  963.             V( g_pEffect->CommitChanges() );
  964.             
  965.             V( pd3dDevice->DrawIndexedPrimitive( D3DPT_TRIANGLELIST, 0, 0, 4 * 6, 0, 6 * 2 ) );
  966.         }
  967.  
  968.         V( g_pEffect->EndPass() );
  969.     }
  970.     V( g_pEffect->End() );
  971. }
  972.  
  973.  
  974. //--------------------------------------------------------------------------------------
  975. // This callback function is called by OnFrameRender
  976. // It performs Stream instancing
  977. //--------------------------------------------------------------------------------------
  978. void OnRenderStreamInstancing( IDirect3DDevice9* pd3dDevice, double fTime, float fElapsedTime )
  979. {
  980.     HRESULT hr;
  981.     UINT iPass, cPasses;
  982.  
  983.     V( pd3dDevice->SetVertexDeclaration( g_pVertexDeclHardware ));
  984.         
  985.     // Stream zero is our model
  986.     V( pd3dDevice->SetStreamSource( 0, g_pVBBox, 0, sizeof(BOX_VERTEX)) );
  987.         
  988.     V( pd3dDevice->SetIndices( g_pIBBox ) );
  989.         
  990.     // Render the scene with this technique
  991.     // as defined in the .fx file
  992.     V( g_pEffect->SetTechnique( g_HandleTechnique ) );
  993.         
  994.     V( g_pEffect->Begin( &cPasses, 0 ) );
  995.     for( iPass = 0; iPass < cPasses; iPass++ )
  996.     {
  997.         V( g_pEffect->BeginPass( iPass ) );
  998.             
  999.         // Render the boxes with the applied technique
  1000.         V( g_pEffect->SetTexture( g_HandleTexture, g_pBoxTexture ) );
  1001.  
  1002.         // The effect interface queues up the changes and performs them 
  1003.         // with the CommitChanges call. You do not need to call CommitChanges if 
  1004.         // you are not setting any parameters between the BeginPass and EndPass.
  1005.         V( g_pEffect->CommitChanges() );
  1006.         
  1007.         for( int nRemainingBoxes = 0; nRemainingBoxes < g_NumBoxes; nRemainingBoxes++ )
  1008.         {   
  1009.             // Stream one is the instancing buffer
  1010.             V( pd3dDevice->SetStreamSource( 1, g_pVBInstanceData, nRemainingBoxes * sizeof( BOX_INSTANCEDATA_POS ), 0 ) );
  1011.  
  1012.             V( pd3dDevice->DrawIndexedPrimitive( D3DPT_TRIANGLELIST, 0, 0, 4 * 6, 0, 6 * 2 ) );
  1013.         }
  1014.             
  1015.         V( g_pEffect->EndPass() );
  1016.     }
  1017.     V( g_pEffect->End() );
  1018. }
  1019.  
  1020.  
  1021. //--------------------------------------------------------------------------------------
  1022. // This callback function will be called at the end of every frame to perform all the 
  1023. // rendering calls for the scene, and it will also be called if the window needs to be 
  1024. // repainted. After this function has returned, the sample framework will call 
  1025. // IDirect3DDevice9::Present to display the contents of the next buffer in the swap chain
  1026. //--------------------------------------------------------------------------------------
  1027. void CALLBACK OnFrameRender( IDirect3DDevice9* pd3dDevice, double fTime, float fElapsedTime )
  1028. {
  1029.     HRESULT hr;
  1030.     D3DXMATRIXA16 mWorld;
  1031.     D3DXMATRIXA16 mView;
  1032.     D3DXMATRIXA16 mProj;
  1033.     
  1034.     // Clear the render target and the zbuffer 
  1035.     V( pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_ARGB(0, 45, 50, 170), 1.0f, 0) );
  1036.     
  1037.     // Render the scene
  1038.     if( SUCCEEDED( pd3dDevice->BeginScene() ) )
  1039.     {
  1040.         // Get the projection & view matrix from the camera class
  1041.         mWorld = *g_Camera.GetWorldMatrix();
  1042.         mProj = *g_Camera.GetProjMatrix();
  1043.         mView = *g_Camera.GetViewMatrix();
  1044.         
  1045.         // Update the effect's variables
  1046.         V( g_pEffect->SetMatrix( g_HandleWorld, &mWorld ) );
  1047.         V( g_pEffect->SetMatrix( g_HandleView, &mView ) );
  1048.         V( g_pEffect->SetMatrix( g_HandleProjection, &mProj ) );
  1049.         
  1050.         switch( g_iRenderTechnique )
  1051.         {
  1052.         case 0:
  1053.             if( DXUTGetDeviceCaps()->VertexShaderVersion >= D3DVS_VERSION(3,0) )
  1054.                 OnRenderHWInstancing( pd3dDevice, fTime, fElapsedTime );
  1055.             break;
  1056.         case 1:
  1057.             OnRenderShaderInstancing( pd3dDevice, fTime, fElapsedTime );
  1058.             break;
  1059.         case 2:
  1060.             OnRenderConstantsInstancing( pd3dDevice, fTime, fElapsedTime );
  1061.             break;
  1062.         case 3:
  1063.             OnRenderStreamInstancing( pd3dDevice, fTime, fElapsedTime );
  1064.         }
  1065.  
  1066.         RenderText();
  1067.         V( g_HUD.OnRender( fElapsedTime ) );
  1068.         V( g_SampleUI.OnRender( fElapsedTime ) );
  1069.         V( g_SampleUI2.OnRender( fElapsedTime ) );
  1070.         
  1071.         V( pd3dDevice->EndScene() );
  1072.     }
  1073. }
  1074.  
  1075.  
  1076. //--------------------------------------------------------------------------------------
  1077. // Render the help and statistics text. This function uses the ID3DXFont interface for 
  1078. // efficient text rendering.
  1079. //--------------------------------------------------------------------------------------
  1080. void RenderText()
  1081. {
  1082.     // The helper object simply helps keep track of text position, and color
  1083.     // and then it calls pFont->DrawText( m_pSprite, strMsg, -1, &rc, DT_NOCLIP, m_clr );
  1084.     // If NULL is passed in as the sprite object, then it will work however the 
  1085.     // pFont->DrawText() will not be batched together.  Batching calls will improves performance.
  1086.     CDXUTTextHelper txtHelper( g_pFont, g_pTextSprite, 15 );
  1087.     
  1088.     // Output statistics
  1089.     txtHelper.Begin();
  1090.     txtHelper.SetInsertionPos( 5, 5 );
  1091.     txtHelper.SetForegroundColor( D3DXCOLOR( 1.0f, 1.0f, 0.0f, 1.0f ) );
  1092.     txtHelper.DrawTextLine( DXUTGetFrameStats() );
  1093.     txtHelper.DrawTextLine( DXUTGetDeviceStats() );
  1094.     
  1095.     txtHelper.SetForegroundColor( D3DXCOLOR( 1.0f, 1.0f, 1.0f, 1.0f ) );
  1096.     if( g_bRuntimeDebug )
  1097.         txtHelper.DrawTextLine( L"WARNING (perf): DEBUG D3D runtime detected!" );
  1098.     if( g_bAppIsDebug )
  1099.         txtHelper.DrawTextLine( L"WARNING (perf): DEBUG application build detected!" );
  1100.     if( g_iRenderTechnique == 0 && DXUTGetDeviceCaps()->VertexShaderVersion < D3DVS_VERSION(3,0) )
  1101.     {
  1102.         txtHelper.SetForegroundColor( D3DXCOLOR( 1.0f, 0.0f, 0.0f, 1.0f ) );
  1103.         txtHelper.DrawTextLine( L"ERROR: Hardware instancing is not supported on non vs_3_0 HW" );
  1104.     }
  1105.  
  1106.     txtHelper.End();
  1107. }
  1108.  
  1109.  
  1110. //--------------------------------------------------------------------------------------
  1111. // Before handling window messages, the sample framework passes incoming windows 
  1112. // messages to the application through this callback function. If the application sets 
  1113. // *pbNoFurtherProcessing to TRUE, then the sample framework will not process this message.
  1114. //--------------------------------------------------------------------------------------
  1115. LRESULT CALLBACK MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, bool* pbNoFurtherProcessing )
  1116. {
  1117.     // Give the dialogs a chance to handle the message first
  1118.     *pbNoFurtherProcessing = g_SampleUI.MsgProc( hWnd, uMsg, wParam, lParam );
  1119.     if( *pbNoFurtherProcessing )
  1120.         return 0;
  1121.     *pbNoFurtherProcessing = g_HUD.MsgProc( hWnd, uMsg, wParam, lParam );
  1122.     if( *pbNoFurtherProcessing )
  1123.         return 0;
  1124.     *pbNoFurtherProcessing = g_SampleUI2.MsgProc( hWnd, uMsg, wParam, lParam );
  1125.     if( *pbNoFurtherProcessing )
  1126.         return 0;
  1127.  
  1128.     // Pass all remaining windows messages to camera so it can respond to user input
  1129.     g_Camera.HandleMessages( hWnd, uMsg, wParam, lParam );
  1130.  
  1131.     return 0;
  1132. }
  1133.  
  1134.  
  1135. //--------------------------------------------------------------------------------------
  1136. // As a convenience, the sample framework inspects the incoming windows messages for
  1137. // keystroke messages and decodes the message parameters to pass relevant keyboard
  1138. // messages to the application.  The framework does not remove the underlying keystroke 
  1139. // messages, which are still passed to the application's MsgProc callback.
  1140. //--------------------------------------------------------------------------------------
  1141. void CALLBACK KeyboardProc( UINT nChar, bool bKeyDown, bool bAltDown )
  1142. {
  1143.     if( bKeyDown )
  1144.     {
  1145.         switch( nChar )
  1146.         {
  1147.             case VK_F1: g_bShowHelp = !g_bShowHelp; break;
  1148.         }
  1149.     }
  1150. }
  1151.  
  1152.  
  1153. //--------------------------------------------------------------------------------------
  1154. // Handles the GUI events
  1155. //--------------------------------------------------------------------------------------
  1156. void CALLBACK OnGUIEvent( UINT nEvent, int nControlID, CDXUTControl* pControl )
  1157. {
  1158.     WCHAR szMessage[100];
  1159.     switch( nControlID )
  1160.     {
  1161.         case IDC_TOGGLEFULLSCREEN: 
  1162.             DXUTToggleFullScreen();
  1163.             break;
  1164.         case IDC_TOGGLEREF:
  1165.             DXUTToggleREF();
  1166.             break;
  1167.         case IDC_CHANGEDEVICE:
  1168.             DXUTSetShowSettingsDialog( !DXUTGetShowSettingsDialog() );
  1169.             break;
  1170.         case IDC_NUMBERBOXES_SLIDER:
  1171.             g_NumBoxes =  g_SampleUI.GetSlider( IDC_NUMBERBOXES_SLIDER )->GetValue();
  1172.             _snwprintf( szMessage, 100, L"# Boxes: %d", g_NumBoxes ); szMessage[99] = 0;
  1173.             g_SampleUI.GetStatic( IDC_NUMBERBOXES_STATIC )->SetText( szMessage );
  1174.             OnDestroyBuffers();
  1175.             OnCreateBuffers( DXUTGetD3DDevice() );
  1176.             break;
  1177.         case IDC_BIND_CPU_SLIDER:
  1178.              g_nBurnCPU = g_SampleUI.GetSlider( IDC_BIND_CPU_SLIDER )->GetValue();
  1179.              g_fBurnAmount = 0.0001f * g_nBurnCPU;
  1180.              _snwprintf( szMessage, 100, L"Goal: %0.1fms/frame", g_fBurnAmount * 1000.0f ); szMessage[99] = 0;
  1181.              g_SampleUI.GetStatic( IDC_BIND_CPU_STATIC )->SetText( szMessage );
  1182.             break;
  1183.         case IDC_RENDERMETHOD_LIST:
  1184.         {
  1185.             DXUTComboBoxItem *pCBItem = g_SampleUI2.GetComboBox( IDC_RENDERMETHOD_LIST )->GetSelectedItem();
  1186.             g_iRenderTechnique = wcscmp( pCBItem->strText, L"Hardware Instancing" ) == 0? 0 :
  1187.                                 wcscmp( pCBItem->strText, L"Shader Instancing" ) == 0? 1 :
  1188.                                 wcscmp( pCBItem->strText, L"Constants Instancing" ) == 0? 2 :
  1189.                                 wcscmp( pCBItem->strText, L"Stream Instancing" ) == 0? 3 : -1;
  1190.  
  1191.             // Note hardware instancing is not supported on non vs_3_0 HW
  1192.             // This sample allows it to be set, but displays an error to the user
  1193.  
  1194.             // recreate the buffers
  1195.             OnDestroyBuffers();
  1196.             OnCreateBuffers( DXUTGetD3DDevice() );
  1197.             break;
  1198.         }
  1199.     }
  1200. }
  1201.  
  1202.  
  1203. //--------------------------------------------------------------------------------------
  1204. // This callback function will be called immediately after the Direct3D device has 
  1205. // entered a lost state and before IDirect3DDevice9::Reset is called. Resources created
  1206. // in the OnResetDevice callback should be released here, which generally includes all 
  1207. // D3DPOOL_DEFAULT resources. See the "Lost Devices" section of the documentation for 
  1208. // information about lost devices.
  1209. //--------------------------------------------------------------------------------------
  1210. void CALLBACK OnLostDevice()
  1211. {
  1212.     if( g_pFont )
  1213.         g_pFont->OnLostDevice();
  1214.     if( g_pEffect )
  1215.         g_pEffect->OnLostDevice();
  1216.     SAFE_RELEASE(g_pTextSprite);
  1217. }
  1218.  
  1219.  
  1220. //--------------------------------------------------------------------------------------
  1221. // This callback function will be called immediately after the Direct3D device has 
  1222. // been destroyed, which generally happens as a result of application termination or 
  1223. // windowed/full screen toggles. Resources created in the OnCreateDevice callback 
  1224. // should be released here, which generally includes all D3DPOOL_MANAGED resources. 
  1225. //--------------------------------------------------------------------------------------
  1226. void CALLBACK OnDestroyDevice()
  1227. {
  1228.     SAFE_RELEASE(g_pEffect);
  1229.     SAFE_RELEASE(g_pFont);
  1230.     SAFE_RELEASE(g_pTextSprite);
  1231.     SAFE_RELEASE(g_pBoxTexture);
  1232.     
  1233.     // destroy vertex/index buffers, vertex declaration
  1234.     OnDestroyBuffers();
  1235. }
  1236.  
  1237.  
  1238.  
  1239.